4.6 接口
接口一般来说在开发一些工具库、框架时比较有用,与Java
等语言不同但是也有类似的地方。
同时接口我们也会用在一些未知类型的判断上面,当我们不知道类型具体是什么时,我们也会使用接口来实现。
在学习本章节前,可以先去学习第五章,之后再来学习这一章会更好
本节代码存放目录为 lesson11
什么是接口
接口在Go
语言中也就是interface
,是一种特殊的数据类型。
我们需要记住的是,接口可以用来表示任意类型,同时接口可以用来定义一组方法合集,之后由结构体去实现。
在之前的章节中,我们学习了变量的声明及定义,如下所示:
var varName varType;
var a int;
那么有了接口之后,我们可以这样定义:
var a interface{}
如上代码所示,就表示a
可以是任意的一种类型,可以是int
、string
、float32
等任一种类型。
在上一节中我们学习了结构体,但是我们没有讲解结构方法,我们将在这一章节中一起讲解。
作为变量类型使用
在上面我们已经输出了定义方式,现在我们来开始测试,如下所示:
var a interface{}
a = 8;
fmt.Println(a)
输出结果如下:
8
在上面的代码中,我们将a
变量的类型定义为interface{}
,之后我们为a
变量赋值为8
,执行代码后没有报错,结果输出了8
。
这样就是一个interface
的简单应用,也就是当我们对于变量的类型未知时,我们可以使用interface
来进行处理。
结构体方法
结构体方法与其他语言类似,当我们定义了一个结构体时,他不仅拥有变量,同时也可以拥有属于他的方法。如下代码所示:
type Dog struct {
Voice string
}
func (d Dog) Speak() {
fmt.Println(d.Voice)
}
dog := Dog{
Voice: "Wang...",
}
dog.Speak()
在上面的代码中,我们定义了一个结构体Dog
,其中包含一个字段Voice
。
在之后,我们又写了一个方法,方法的作用是将结构体的Voice
字段打印出来:
func (d Dog) Speak() {
fmt.Println(d.Voice)
}
上面的代码就演示了结构体方法是如何使用的。
在前面我们讲到,结构体可以通过符号:.
来引用结构体的字段,那么同样的,方法也是一样的来处理。
当我们声明结构体变量后,为Voice
赋值,之后通过结构体变量dog
直接调用:dog.Speak()
即可。
结果输出如下:
Wang!
接口及结构体方法使用
上面我们讲到了结构体方法的使用,那么如果我们有很多的结构体都有相同的方法应该怎么处理呢?
比如说我们有很多个小动物的结构体,同时都需要调用结构体的Speak
这时候再像上面的一样去处理也是可以实现的,但是代码复杂度就会增高。
那么这里就涉及到了接口的多态性,如下代码所示:
type Animal interface {
Speak()
}
type Dog struct {
Voice string
}
func (d Dog) Speak() {
fmt.Println(d.Voice)
}
type Cat struct {
Voice string
}
func (c Cat) Speak() {
fmt.Println(c.Voice)
}
var animalDog Animal = Dog{
Voice: "Wang...",
}
animalDog.Speak()
var animalCat Animal = Cat{
Voice: "Miao...",
}
animalCat.Speak()
如上代码所示,首先我们定义了Animal
的接口,接口里面有一个方法:Speak
另外我们定义了Dog
、Cat
两个结构体,两个结构体都实现了Speak
方法。
由于Animal
是一个interface
,而interface
又具有任意类型的特性。
所以我们可以直接声明:var animalDog Animal = Dog{}
、以及var animalCat Animal = Cat{}
这样我们就可以很容易的调用:animalDog.Speak()
、animalCat.Speak()
来进行对应的输出。
那么看到这里可能会有个疑问,为什么要这么做呢?直接使用dog.Speak
、cat.Speak
同样可以实现相同效果,为什么反而要使用interface
来进行更复杂的操作呢?
我们直接看下面的代码:
func animalSpeak(animal Animal) {
animal.Speak()
}
var animalDog1 Animal = Dog{
Voice: "Wang...",
}
animalSpeak(animalDog1)
var animalCat1 Animal = Cat{
Voice: "Miao...",
}
animalSpeak(animalCat1)
在上面的代码中,我们首先定义了一个函数:animalSpeak
,函数接收Animal
类型的参数。
之后我们同样声明了:animalDog1
、animalSpeak
,之后将这两个变量作为参数传递给了animalSpeak
结果输出如下:
Wang...
Miao...
从上面的代码我们可以看出,使用interface
以及结构体方法来配合的方式,就是为了可以让代码更加通用、扩展。
在这里我们举例比较简单,所以看不出太大的区别,但是如果在实际工程中,这样的场景运用就会特别多。
比如我们现在需要新增几种小动物,那么我们就不需要再去修改现在的代码,而是新增结构体实现了Speak
即可。
小结
Go
语言接口interface
在实际应用中比较广泛,主要在实际的工程项目中使用的比较多。
比如开发API
接口、请求第三方API
获取数据等,都会经常用到这个特殊类型。
经过本节学习,总结如下:
接口可以是任意类型的
接口常与结构体方法来配合使用
结构体方法必须实现接口所定义的所有方法
可以参照
Java
的接口来理解,但是稍微有一点不同